package com.xnyzc.lhy.common.component.redis;

import com.xnyzc.lhy.common.constant.RedisPrefixConstant;
import com.xnyzc.lhy.common.exception.PangException;
import com.xnyzc.lhy.common.penum.EErrorCode;
import com.xnyzc.lhy.common.penum.EOrderType;
import com.xnyzc.lhy.common.util.CheckUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: huxuekuo
 * @Date: 2019-07-27 10:25
 * @Description:
 */
@Slf4j
@Component
public class RedisCommon {

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     *  存储list
     * @param key
     * @param list
     */
    public void setList(String key,List<String> list,Long second){
        redisTemplate.opsForList().rightPushAll(key, list);
        if (second != null) {
            redisTemplate.expire(key, second, TimeUnit.SECONDS);
        }
    }
    public void setList(String key,List<String> list){
        redisTemplate.opsForList().rightPushAll(key, list);
    }

    /**
     * 取出list
     * @param key
     * @return
     */
    public List<String> getList(String key){
        List<String> list = redisTemplate.opsForList().range(key, 0, -1);
        return list;
    }
    /**
     * hashMap类型存储,过期时间设置
     *
     * @param key
     * @param hashMap
     * @return
     */
    public boolean setHashMap(String key, HashMap hashMap, Long second) {
        try {
            redisTemplate.opsForHash().putAll(key, hashMap);
            if (second != null) {
                redisTemplate.expire(key, second, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 依据key获取hashMap
     *
     * @param key
     * @return
     */
    public HashMap getHashMap(String key) {
        try {
            HashMap entries = (HashMap) redisTemplate.opsForHash().entries(key);
            return entries;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 保存Hash
     */
    public void setHashElement(String key, String hashKey) {
        try {
            if (!redisTemplate.hasKey(key)) {
                Map<String, Integer> map = new HashMap<>(8);
                redisTemplate.opsForHash().putAll(key, map);
            }

            if (redisTemplate.opsForHash().hasKey(key, hashKey)) {
                int num = (int) redisTemplate.opsForHash().get(key, hashKey);
                redisTemplate.opsForHash().put(key, hashKey, num + 1);
            } else {
                redisTemplate.opsForHash().put(key, hashKey, 1);
            }
        } catch (Exception e) {
            log.error("{}", e);
        }
    }

    public void setEstimateCount(String key) {
        try {
            if (hashKey(key)) {
                redisTemplate.opsForValue().increment(key, 1);
            } else {
                redisTemplate.opsForValue().set(key, 1);
            }
        } catch (Exception e) {
            log.error("{}", e);
        }
    }

    /**
     * String类型添加数据
     */
    public boolean set(String key, String value) {
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * String类型添加数据设置过期时长
     */
    public boolean set(String key, String value, int time) {
        try {
            redisTemplate.opsForValue().set(key, value);
            if (time != 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 设置秒
     *
     * @param key
     * @param time
     * @return
     */
    public boolean expire(String key, int time) {
        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    public ValueOperations<String, String> redis() {
        return redisTemplate.opsForValue();
    }

    /**
     * 删除Key
     *
     * @param key
     * @return
     */
    public boolean remove(String key) {
        if (hashKey(key)) {
            return redisTemplate.delete(key);
        }
        return false;
    }

    /**
     * 根据Key获取数据
     *
     * @param key key
     * @return 有值返回值, 没有返回null
     */
    public String getStr(String key) {
        String result = redis().get(key);
        if (StringUtils.isNotEmpty(result)) {
            return result;
        }
        return null;
    }

    /**
     * 模糊查询key
     *
     * @param keyPatter 模糊查询表达式
     * @return
     */
    public Set<String> keysPatter(String keyPatter) {
        Set<String> keys = redisTemplate.keys(keyPatter);
        if (!Objects.isNull(keys)) {
            return keys;
        }
        return null;
    }

    /**
     * 判断Key是否存在
     *
     * @param str
     * @return
     */
    public boolean hashKey(String str) {
        return redisTemplate.hasKey(str);
    }

    /**
     * 模糊查询Key
     *
     * @param keys
     * @return
     */
    public Set<String> keys(String keys) {
        return redisTemplate.keys(keys);
    }

    /**
     * 解析规定的Redis Key
     *
     * @param key    key
     * @param prefix 规定好的前缀,否则报错
     * @return
     */
    public String analysisRedisKey(String key, String prefix) {
        if (hashKey(key)) {
            String[] keys = key.split(prefix);
            if (!CheckUtil.arrayIsEmpty(keys)) {
                return keys[1];
            }
        }
        return null;
    }

    /**
     * 根据订单号判断叫车类型前缀
     *
     * @param orderNo 订单号
     * @return 前缀
     */
    public String getOrderPrefix(String orderNo) {
        if (orderNo.contains(EOrderType.ZFJC.getValue())) {
            return RedisPrefixConstant.ORDER_PERSONAL_KEY_PREFIX;
        } else if (orderNo.contains(EOrderType.GRGW.getValue())) {
            return RedisPrefixConstant.ORDER_PERSONAL_OFFICIAL_KEY_PREFIX;
        } else if (orderNo.contains(EOrderType.SPGW.getValue())) {
            return RedisPrefixConstant.ORDER_APPROVAL_OFFICIAL_KEY_PREFIX;
        } else if (orderNo.contains(EOrderType.BMGW.getValue())) {
            return RedisPrefixConstant.ORDER_DEPT_OFFICIAL_KEYP_REFIX;
        }
        throw PangException.create(EErrorCode.noData);
    }

    public void set(String key, String value, Long expireSecond) {
        redis().set(key, value, expireSecond, TimeUnit.SECONDS);
    }

    public Long getExpire(String key) {
        Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
        return expire;
    }


    public void addGeos(Map<String, Point> map, String key) {//批量添加
        //redisTemplate.opsForGeo().geoAdd(key,map);
        redisTemplate.opsForGeo().add(key, map);
    }


    public Map geoRadius(double distance, double lng, double lat, String key) {
        Map<String, Object> result = new HashMap<>();
        List<String> keys = new ArrayList<>();
        GeoOperations<String, String> geoOps = redisTemplate.opsForGeo();
        //设置geo查询参数
        RedisGeoCommands.GeoRadiusCommandArgs geoRadiusArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
        geoRadiusArgs = geoRadiusArgs.includeCoordinates().includeDistance();//查询返回结果包括距离和坐标
        geoRadiusArgs.sortAscending();//按查询出的坐标距离中心坐标的距离进行排序
        geoRadiusArgs.limit(100);//限制查询数量

//        GeoResults<RedisGeoCommands.GeoLocation<String>> radiusGeo = geoOps.geoRadius(
//                key,
//                new Circle(new Point(lng, lat), new Distance(distance, RedisGeoCommands.DistanceUnit.METERS)),
//                geoRadiusArgs);
//        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = radiusGeo.getContent();
//        for (GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult : content) {
//            RedisGeoCommands.GeoLocation<String> content1 = geoLocationGeoResult.getContent();
//            keys.add(content1.getName());
//        }
        GeoResults<RedisGeoCommands.GeoLocation<String>> radiusGeo = geoOps.radius(
                key,
                new Circle(new Point(lng, lat), new Distance(distance, RedisGeoCommands.DistanceUnit.METERS)),
                geoRadiusArgs);
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = radiusGeo.getContent();
        for (GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult : content) {
            RedisGeoCommands.GeoLocation<String> content1 = geoLocationGeoResult.getContent();
            keys.add(content1.getName());
        }
        result.put("keys", keys);
        result.put("distance", radiusGeo.getAverageDistance());
        return result;
    }

    public void addToZSet(String zkey, String id, long score) {
        redisTemplate.opsForZSet().add(zkey, id, score);
    }

    public Set<String> getFromZSet(String zkey, long minScore, long maxScore) {
        return redisTemplate.opsForZSet().rangeByScore(zkey, minScore, maxScore);
    }

    public long getZSetCount(String zkey, long minScore, long maxScore) {
        return redisTemplate.opsForZSet().count(zkey, minScore, maxScore);
    }

    public boolean delFromZSet(String zkey, String id) {
        Long res = redisTemplate.opsForZSet().remove(zkey, id);
        return res != null && res > 0;
    }

    public double getScoreFromZSet(String zkey, String id) {
        Double res = redisTemplate.opsForZSet().score(zkey, id);
        if (res == null) {
            return 0d;
        } else {
            return res;
        }
    }

    public List<String> multiGet(Set<String> keys) {
        List<String> values = redisTemplate.opsForValue().multiGet(keys);
        return values;
    }
}
